<!DOCTYPE html>
<html lang="en">
  <head>
    <title>
        Java-Se-多线程-1-基础 - rulerLwx Blog
      </title>
        <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
    <meta name="renderer" content="webkit">
    <meta http-equiv="Cache-Control" content="no-transform" />
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="format-detection" content="telephone=no,email=no,adress=no">
    
    <meta name="theme-color" content="#000000" />
    
    <meta http-equiv="window-target" content="_top" />
    
    
    <meta name="description" content="进程 &amp;amp; 线程 进程：是系统进行资源分配的和调度的一个独立单位。举例：将公司的一个部门看作一个进程，公司分配项目奖金的时候就是以部门为基本单位分配" />
    <meta name="generator" content="Hugo 0.73.0 with theme pure" />
    <title>Java-Se-多线程-1-基础 - rulerLwx Blog</title>
    
    
    <link rel="stylesheet" href="https://rulerLwx.gitee.io/css/style.min.c4bc7071f132c964c2116bca53b392933f377e5ca7b7051ed245187c621a2d3e.css">
    
    <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/9.15.10/styles/github.min.css" async>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.css" async>
    <meta property="og:title" content="Java-Se-多线程-1-基础" />
<meta property="og:description" content="进程 &amp; 线程 进程：是系统进行资源分配的和调度的一个独立单位。举例：将公司的一个部门看作一个进程，公司分配项目奖金的时候就是以部门为基本单位分配" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://rulerLwx.gitee.io/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-1-%E5%9F%BA%E7%A1%80/" />
<meta property="article:published_time" content="2020-07-01T18:58:47+08:00" />
<meta property="article:modified_time" content="2020-07-01T18:58:47+08:00" />
<meta itemprop="name" content="Java-Se-多线程-1-基础">
<meta itemprop="description" content="进程 &amp; 线程 进程：是系统进行资源分配的和调度的一个独立单位。举例：将公司的一个部门看作一个进程，公司分配项目奖金的时候就是以部门为基本单位分配">
<meta itemprop="datePublished" content="2020-07-01T18:58:47&#43;08:00" />
<meta itemprop="dateModified" content="2020-07-01T18:58:47&#43;08:00" />
<meta itemprop="wordCount" content="7185">



<meta itemprop="keywords" content="多线程," /><meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Java-Se-多线程-1-基础"/>
<meta name="twitter:description" content="进程 &amp; 线程 进程：是系统进行资源分配的和调度的一个独立单位。举例：将公司的一个部门看作一个进程，公司分配项目奖金的时候就是以部门为基本单位分配"/>

    <!--[if lte IE 9]>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/classlist/1.1.20170427/classList.min.js"></script>
      <![endif]-->

    <!--[if lt IE 9]>
        <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
      <![endif]-->
  </head>

  
  

  <body class="main-center theme-black" itemscope itemtype="http://schema.org/WebPage"><header class="header" itemscope itemtype="http://schema.org/WPHeader">
    <div class="slimContent">
      <div class="navbar-header">
        <div class="profile-block text-center">
          <a id="avatar" href="https://gitee.com/rulerLwx" target="_blank">
            <img class="img-circle img-rotate" src="https://rulerLwx.gitee.io/avatar.png" width="200" height="200">
          </a>
          <h2 id="name" class="hidden-xs hidden-sm">rulerLwx</h2>
          <h3 id="title" class="hidden-xs hidden-sm hidden-md">thinking...</h3>
          <small id="location" class="text-muted hidden-xs hidden-sm"><i class="icon icon-map-marker"></i>Guangzhou, China</small>
        </div><div class="search" id="search-form-wrap">
    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="Search" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat" onclick="return false;"><i
                        class="icon icon-search"></i></button>
            </span>
        </div>
        <div class="ins-search">
            <div class="ins-search-mask"></div>
            <div class="ins-search-container">
                <div class="ins-input-wrapper">
                    <input type="text" class="ins-search-input" placeholder="Type something..."
                        x-webkit-speech />
                    <button type="button" class="close ins-close ins-selectable" data-dismiss="modal"
                        aria-label="Close"><span aria-hidden="true">×</span></button>
                </div>
                <div class="ins-section-wrapper">
                    <div class="ins-section-container"></div>
                </div>
            </div>
        </div>
    </form>
</div>
        <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
          <span class="sr-only">Toggle navigation</span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
      </div>
      <nav id="main-navbar" class="collapse navbar-collapse" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation">
        <ul class="nav navbar-nav main-nav">
            <li class="menu-item menu-item-home">
                <a href="/">
                    <i class="icon icon-home-fill"></i>
                  <span class="menu-title">Home</span>
                </a>
            </li>
            <li class="menu-item menu-item-archives">
                <a href="/posts/">
                    <i class="icon icon-archives-fill"></i>
                  <span class="menu-title">Archives</span>
                </a>
            </li>
            <li class="menu-item menu-item-categories">
                <a href="/categories/">
                    <i class="icon icon-folder"></i>
                  <span class="menu-title">Categories</span>
                </a>
            </li>
            <li class="menu-item menu-item-tags">
                <a href="/tags/">
                    <i class="icon icon-tags"></i>
                  <span class="menu-title">Tags</span>
                </a>
            </li>
            <li class="menu-item menu-item-about">
                <a href="/about/">
                    <i class="icon icon-cup-fill"></i>
                  <span class="menu-title">About</span>
                </a>
            </li>
        </ul>
      </nav>
    </div>
  </header>

<aside class="sidebar" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    
      <div class="widget">
    <h3 class="widget-title">Board</h3>
    <div class="widget-body">
        <div id="board">
            <div class="content">enjoy~
            </div>
        </div>
    </div>
</div>

      <div class="widget">
    <h3 class="widget-title"> Categories</h3>
    <div class="widget-body">
        <ul class="category-list">
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-framework/" class="category-list-link">java-framework</a><span class="category-list-count">38</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-front-end/" class="category-list-link">java-front-end</a><span class="category-list-count">11</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-se/" class="category-list-link">java-se</a><span class="category-list-count">21</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/java-senior/" class="category-list-link">java-senior</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/linux/" class="category-list-link">linux</a><span class="category-list-count">13</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/tools/" class="category-list-link">tools</a><span class="category-list-count">1</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%8A%80%E6%9C%AF%E6%9D%82%E7%83%A9/" class="category-list-link">技术杂烩</a><span class="category-list-count">4</span></li>
            <li class="category-list-item"><a href="https://rulerLwx.gitee.io/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-list-link">数据库</a><span class="category-list-count">15</span></li>
        </ul>
    </div>
</div>
      <div class="widget">
    <h3 class="widget-title"> Tags</h3>
    <div class="widget-body">
        <ul class="tag-list">
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/jvm/" class="tag-list-link">jvm</a><span
                    class="tag-list-count">1</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" class="tag-list-link">多线程</a><span
                    class="tag-list-count">2</span></li>
            
            
            <li class="tag-list-item"><a href="https://rulerLwx.gitee.io/tags/%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/" class="tag-list-link">网络编程</a><span
                    class="tag-list-count">3</span></li>
            
        </ul>

    </div>
</div>
      
<div class="widget">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget-body">
        <ul class="recent-post-list list-unstyled no-thumbnail">
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%87%AA%E5%B7%B1%E5%8A%A8%E6%89%8B%E4%B8%80%E6%89%B9%E9%87%8F%E7%A7%BB%E5%8A%A8%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6/" class="title">自己动手（一）——批量移动、重命名文件</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-27 17:50:02 &#43;0800 CST" itemprop="datePublished">2020-07-27</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E5%85%B3%E4%BA%8Einteger%E7%9A%84-128~127%E7%BC%93%E5%AD%98/" class="title">关于Integer的 -128~127缓存</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-11 16:56:21 &#43;0800 CST" itemprop="datePublished">2020-07-11</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98/" class="title">跨域问题</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-08 22:41:12 &#43;0800 CST" itemprop="datePublished">2020-07-08</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/" class="title">个人博客搭建</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-05 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-05</time>
                    </p>
                </div>
            </li>
            <li>
                <div class="item-inner">
                    <p class="item-title">
                        <a href="https://rulerLwx.gitee.io/2020/07/centos/" class="title">CentOS-</a>
                    </p>
                    <p class="item-date">
                        <time datetime="2020-07-01 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-01</time>
                    </p>
                </div>
            </li>
        </ul>
    </div>
</div>
  </div>
</aside>

    
    
<aside class="sidebar sidebar-toc collapse" id="collapseToc" itemscope itemtype="http://schema.org/WPSideBar">
  <div class="slimContent">
    <h4 class="toc-title">Catalogue</h4>
    <nav id="toc" class="js-toc toc">

    </nav>
  </div>
</aside>
<main class="main" role="main"><div class="content">
  <article id="-" class="article article-type-" itemscope
    itemtype="http://schema.org/BlogPosting">
    
    <div class="article-header">
      <h1 itemprop="name">
  <a
    class="article-title"
    href="/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-1-%E5%9F%BA%E7%A1%80/"
    >Java-Se-多线程-1-基础</a
  >
</h1>

      <div class="article-meta">
        
<span class="article-date">
  <i class="icon icon-calendar-check"></i>&nbsp;
<a href="https://rulerLwx.gitee.io/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-1-%E5%9F%BA%E7%A1%80/" class="article-date">
  <time datetime="2020-07-01 18:58:47 &#43;0800 CST" itemprop="datePublished">2020-07-01</time>
</a>
</span>
<span class="article-category">
  <i class="icon icon-folder"></i>&nbsp;
  <a class="article-category-link" href="/categories/java-se/"> Java-Se </a>
</span>  
  <span class="article-tag">
    <i class="icon icon-tags"></i>&nbsp;
    <a class="article-tag-link" href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"> 多线程 </a>
  </span>

        <span class="post-comment"><i class="icon icon-comment"></i>&nbsp;<a href="/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-1-%E5%9F%BA%E7%A1%80/#comments"
            class="article-comment-link">Comments</a></span>
		<span class="post-wordcount hidden-xs" itemprop="wordCount">Word Count: 7185words</span>
		<span class="post-readcount hidden-xs" itemprop="timeRequired">Read Count: 15minutes </span>
      </div>
    </div>
    <div class="article-entry marked-body js-toc-content" itemprop="articleBody">
      <h1 id="进程--线程">进程 &amp; 线程</h1>
<p>进程：是系统进行资源分配的和调度的一个独立单位。举例：将公司的一个部门看作一个进程，公司分配项目奖金的时候就是以部门为基本单位分配1万块钱，部门下面的十几个人就分这1万块钱，这时就可以将部门中的每个人看作是一个线程。这就是进程与线程之间的关系。</p>
<p>线程：线程是进程的执行单元，一个进程可以有多个线程。</p>
<p>进程间可以并发，线程间也可以并发。</p>
<p>什么是并发，什么是并行？？？？？</p>
<blockquote>
<p>并发（concurrency）和并行（parallellism）是：
解释一：并行是指两个或者多个事件在同一时刻发生；而并发是指两个或多个事件在同一时间间隔发生。
解释二：并行是在不同实体上的多个事件，并发是在同一实体上的多个事件。
解释三：在一台处理器上“同时”处理多个任务，在多台处理器上同时处理多个任务。如hadoop分布式集群
所以并发编程的目标是充分的利用处理器的每一个核，以达到最高的处理性能。&ndash; <a href="http://ifeve.com/parallel_and_con/">并发编程网</a></p>
</blockquote>
<p>因此，多线程编程解决的是并发问题，并行的问题可以通过分布式部署来解决。？？？</p>
<h1 id="创建线程的3种方式">创建线程的3种方式</h1>
<h2 id="继承thread类">继承Thread类</h2>
<p>步骤：<br>
1、 定义Thread类的子类，并重写run()方法。<br>
2、 创建Thread子类的实现<br>
3、 调用线程对象的start()方法启动线程</p>
<p>代码片段：</p>
<pre><code class="language-java">
// 通过继承Thread类来创建线程类
public class FirstThread extends Thread
{
    // 重写run方法，run方法的方法体就是线程执行体
    public void run()
    {

    }
    public static void main(String[] args)
    {
        // 创建、并启动第一条线程
        new FirstThread().start();
        // 创建、并启动第二条线程
        new FirstThread().start();
    }
}

</code></pre>
<h2 id="实现runnable接口">实现Runnable接口</h2>
<p>步骤：<br>
1、定义Runnable接口的实现类，并重写该接口的run()方法<br>
2、创建该实现类的实例，并以此实例作为Thread的target来创建Thread对象<br>
3、调用该线程对象的start()方法来启动线程</p>
<p>代码片段：</p>
<pre><code class="language-java">
// 通过实现Runnable接口来创建线程类
public class SecondThread implements Runnable
{
    // run方法同样是线程执行体
    public void run()
    {
       
    }

    public static void main(String[] args)
    {
       SecondThread st = new SecondThread();     // ①
        // 通过new Thread(target , name)方法创建新线程
        new Thread(st , &quot;新线程1&quot;).start();
        new Thread(st , &quot;新线程2&quot;).start();
    }
}
</code></pre>
<h2 id="callable和future">Callable和Future</h2>
<p>步骤：<br>
1、创建Callable接口实现类，并实现call()方法<br>
2、使用FutureTask类来包装Callable对象<br>
3、使用FutureTask对象作为Thread对象的target创建并启动线程<br>
4、通过FutureTask对象的get()方法获取线程的返回值</p>
<p>代码片段：</p>
<pre><code class="language-java">    @Test
    public void test() throws Exception {
        FutureTask&lt;Integer&gt; task = new FutureTask&lt;Integer&gt;(new Callable&lt;Integer&gt;() {

            public Integer call() throws Exception {
                return 1;
            }
        });

        new Thread(task, &quot;新的线程1&quot;).start();

        Integer i = task.get();
        System.out.println(&quot;i:&quot; + i);
    }
</code></pre>
<h1 id="线程生命周期">线程生命周期</h1>
<p>线程的生命周期有：新建、就绪、运行、阻塞、死亡。</p>
<p>线程对象调用start()方法后就处于就绪状态。</p>
<p>线程生命周期的状态转换图如下：
<img src="https://oscimg.oschina.net/oscnet/8ce3055225ac17367c264516865b450b4f9.jpg" alt="线程生命周期状态转换图" title="线程生命周期状态转换图"></p>
<p><strong>总结：</strong></p>
<ul>
<li>wait()，进入阻塞状态，释放同步监视器</li>
<li>sleep()，进入阻塞状态，给其它进程（不管线程优先级）执行的机会，不会释放同步监视器</li>
<li>join()，进入阻塞状态，直到加入的线程执行完成为止</li>
<li>yield()，不进入阻塞状态，给其它线程（只给优先级高）执行的机会，不会释放同步监视器</li>
</ul>
<h1 id="控制线程">控制线程</h1>
<h2 id="join">join</h2>
<p>join：让一个线程等待另一个线程完成。</p>
<h2 id="setdaemontrue">setDaemon(true)</h2>
<p>设置为后台线程，调用线程实例本身的setDaemon()方法：</p>
<pre><code class="language-java">        MyThread myThread = new MyThread();
        myThread.setDaemon(true);
</code></pre>
<h2 id="sleep">sleep</h2>
<p>线程睡眠，并进入阻塞状态。</p>
<p>调用线程Thread类的静态sleep()方法，而不是某个线程的实例方法：</p>
<pre><code class="language-java">Thread.sleep(1000);
</code></pre>
<h2 id="yield">yield</h2>
<p>线程暂停，但不进入阻塞状态。</p>
<p>调用线程Thread类的静态yield()方法，而不是某个线程的实例方法：</p>
<pre><code>Thread.yield();
</code></pre>
<h2 id="sleep与yield区别">sleep()与yield()区别</h2>
<ul>
<li>sleep()与yield()都会让当前线程暂停，sleep()会给其它线程执行的机会，不理会其它线程的优先级；但yield()只给优先级相同或更高的线程执行的机会。</li>
<li>sleep()会让线程进入阻塞状态，yield()则不会进入阻塞状态。</li>
</ul>
<h2 id="线程优先级">线程优先级</h2>
<p>priority，1-10，数值越大优先级越高：</p>
<ul>
<li>MAX_PRIORITY:10</li>
<li>MIN_PRIORITY:1</li>
<li>NORM_PRIORITY:5</li>
</ul>
<pre><code>    myThread.setPriority(Thread.MAX_PRIORITY);
</code></pre>
<p><em>注：servlet中的 load-on-startup 参数，值越大优先级越低</em></p>
<h1 id="线程同步">线程同步</h1>
<h2 id="传统线程同步">传统线程同步</h2>
<h3 id="同步方法">同步方法</h3>
<p>同步一个易发生线程安全的方法，<strong>这里的锁就是this，即当前类对象</strong>：</p>
<pre><code class="language-java">    // 提供一个线程安全draw()方法来完成取钱操作
    public synchronized void draw(double drawAmount)
    {
        
    }
</code></pre>
<h3 id="同步代码块">同步代码块</h3>
<p>同步一个易发生线程安全的字段，<strong>这里的锁就是此可能发生线程安全的字段</strong>：</p>
<pre><code class="language-java">
public class DrawThread extends Thread
{
    // 模拟用户账户
    private Account account;

    // 当多条线程修改同一个共享数据时，将涉及数据安全问题。
    public void run()
    {
        // 使用account作为同步监视器，任何线程进入下面同步代码块之前，
        // 必须先获得对account账户的锁定——其他线程无法获得锁，也就无法修改它
        // 这种做法符合：“加锁 → 修改 → 释放锁”的逻辑
        synchronized (account)
        {
           
        }
        // 同步代码块结束，该线程释放同步锁
    }
}

</code></pre>
<h3 id="何时释放同步监视器">何时释放同步监视器</h3>
<ul>
<li>wait()方法会释放同步监视器</li>
<li>Thread.sleep(),Thread.yield()不会释放同步监视器</li>
</ul>
<h2 id="同步锁lock">同步锁（Lock）</h2>
<p>java5开始提供了同步锁，常用的同步锁是ReentrantLock。</p>
<p>同步锁继承关系如下：</p>
<pre><code>- Lock
    |-ReentrantLock
- ReadWriteLock
    |-ReentrantReadWriteLock
</code></pre>
<p>同步锁使用代码片段：</p>
<pre><code class="language-java">
import java.util.concurrent.locks.*;

public class Account
{
    // 定义锁对象
    private final ReentrantLock lock = new ReentrantLock();

    // 提供一个线程安全draw()方法来完成取钱操作
    public void draw(double drawAmount)
    {
        // 加锁
        lock.lock();
        try
        {

        }
        finally
        {
            // 修改完成，释放锁
            lock.unlock();
        }
    }
}
</code></pre>
<h2 id="threadlocal">ThreadLocal</h2>
<p>原理：为每一个使用该变量的线程都提供一个变量值的副本，使每一个线程都可以独立改变自己的副本，而不会和其他线程的副本冲突，就好像每一个线程都完全拥有该变量一样。代码内部使用ThreadLocal.ThreadLocalMap来存储变量的键和值，也就是内部使用一个类似Map的结构来存储name和name对应的值。</p>
<p>ThreadLocal只提供三个public方法：</p>
<ul>
<li>T get()：返回此线程局部变量中当前线程副本中的值。</li>
<li>void remove()：删除此线程局部变量中当前线程副本中的值。</li>
<li>void set(T value)：设置此线程局部变量中当前线程副本中的值。</li>
</ul>
<p>示例：</p>
<pre><code class="language-java">class Acount
{
    private ThreadLocal&lt;String&gt; name = new ThreadLocal&lt;&gt;();
    public Acount(String str){
        this.name.set(str);
    }
    public String getName(){
        return name.get();
    }
    public void setName(String str){
        this.name.set(str);
    }
    //......
}
</code></pre>
<h1 id="线程间通信">线程间通信</h1>
<h2 id="传统线程间通信">传统线程间通信</h2>
<p>适用条件：如果程序中使用的是同步代码块、同步方法来控制线程安全，则线程间的通信是使用Object类的 wait(),notify(),notifyAll()控制线程间通信。</p>
<ul>
<li>wait() ：当前线程等待</li>
<li>notify() ：唤醒在此同步监视器上的一个线程（或随机选择一个）</li>
<li>notifyAll() ：唤醒在此同步监视器上的所有线程，但只有一个获得执行机会</li>
</ul>
<pre><code class="language-java">
public class Account
{
    // 封装账户编号、账户余额的两个成员变量
    private String accountNo;
    private double balance;
    // 标识账户中是否已有存款的旗标
    private boolean flag = false;

    public Account(){}
    // 构造器
    public Account(String accountNo , double balance)
    {
        this.accountNo = accountNo;
        this.balance = balance;
    }

    // accountNo的setter和getter方法
    public void setAccountNo(String accountNo)
    {
        this.accountNo = accountNo;
    }
    public String getAccountNo()
    {
        return this.accountNo;
    }
    // 因此账户余额不允许随便修改，所以只为balance提供getter方法，
    public double getBalance()
    {
        return this.balance;
    }

    public synchronized void draw(double drawAmount)
    {
        try
        {
            // 如果flag为假，表明账户中还没有人存钱进去，取钱方法阻塞
            if (!flag)
            {
                wait();
            }
            else
            {
                // 执行取钱
                System.out.println(Thread.currentThread().getName()
                    + &quot; 取钱:&quot; +  drawAmount);
                balance -= drawAmount;
                System.out.println(&quot;账户余额为：&quot; + balance);
                // 将标识账户是否已有存款的旗标设为false。
                flag = false;
                // 唤醒其他线程
                notifyAll();
            }
        }
        catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }
    }
    public synchronized void deposit(double depositAmount)
    {
        try
        {
            // 如果flag为真，表明账户中已有人存钱进去，则存钱方法阻塞
            if (flag)             //①
            {
                wait();
            }
            else
            {
                // 执行存款
                System.out.println(Thread.currentThread().getName()
                    + &quot; 存款:&quot; +  depositAmount);
                balance += depositAmount;
                System.out.println(&quot;账户余额为：&quot; + balance);
                // 将表示账户是否已有存款的旗标设为true
                flag = true;
                // 唤醒其他线程
                notifyAll();
            }
        }
        catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }
    }
}
</code></pre>
<h2 id="使用condition控制线程间通信">使用Condition控制线程间通信</h2>
<p>适用条件：如果程序中使用的是同步锁（Lock）来控制线程安全，则线程间通信是使用Condition来控制线程间通信。</p>
<p>获取Condiion实例代码片段：通过锁去获取</p>
<pre><code class="language-java">        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();
</code></pre>
<p>Condition类提供如下方法以实现线程间通信：</p>
<ul>
<li>await()</li>
<li>signal(),唤醒单个线程</li>
<li>signalAll()，唤醒此Lock上的所有线程</li>
</ul>
<p>示例：</p>
<pre><code class="language-java">
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

public class Account
{
    // 显式定义Lock对象
    private final Lock lock = new ReentrantLock();
    // 获得指定Lock对象对应的Condition
    private final Condition cond  = lock.newCondition();

    public void draw(double drawAmount)
    {
        // 加锁
        lock.lock();
        try
        {
            if ()
            {
                
            }
            else
            {
                // 唤醒其他线程
                cond.signalAll();
            }
        }
        catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }
        // 使用finally块来释放锁
        finally
        {
            lock.unlock();
        }
    }
}
</code></pre>
<h2 id="使用阻塞队列bockingqueue控制线程间通信">使用阻塞队列（BockingQueue）控制线程间通信</h2>
<p>todo&hellip;</p>
<h1 id="线程组与异常处理">线程组与异常处理</h1>
<p>todo&hellip;</p>
<h1 id="线程池">线程池</h1>
<h2 id="普通线程池">普通线程池</h2>
<p>java 5 新增了一个 Executors 工厂类来产生线程池，常用以下几个静态方法：</p>
<ul>
<li>ExecutorService newCachedThreadPool()：系统根据需要创建一个具有缓存功能的线程池。</li>
<li>ExecutorService newFixedThreadPool(int nThreads)：创建一个可重用的、固定线程数的线程池。</li>
<li>ExecutorService newSingleThreadExector()：创建一个只有单个线程的线程池。</li>
<li>ScheduledExecutorService newScheduledThreadPool(int corePoolSize)：创建指定线程数的线程池，它可以指定延迟后执行线程任务。</li>
<li>ScheduledExecutorService newSingleThreadScheduledExecutor()：创建一个只有一个线程和线程池，它可以在指定延迟后执行线程任务。</li>
<li>ExecutorService newWorkStealingPool(int parallelism)：创建持有足够的线程的线程池来支持给定的并行级别，该方法还会使用多个队列来减少竞争。（java 8）</li>
<li>ExecutorService newWorkStealingPool()：该方法是前一个方法的简化版本。如果当前机器有4个CPU，则目标并行级别被设置为4，也就是相当于前一个方法传入4作为参数。（java 8）</li>
</ul>
<p>ExecutorService 代表尽快执行线程的线程池，程序只需把一个 Runnable 对象或 Callable 对象提交给指定的线程池即可。</p>
<p>ExecutorService 常用以下方法：</p>
<ul>
<li>Future&lt;?&gt; submit(Runnable task)：将一个线程任务提交给线程池，Future代表返回值。</li>
<li><!-- raw HTML omitted --> Future<!-- raw HTML omitted --> submit(Runnable task,T result)：同上，其中result显式指定线程执行执行结束后返回的值。</li>
<li><!-- raw HTML omitted --> Future<!-- raw HTML omitted --> submit(Callable<!-- raw HTML omitted --> task)：将一个Calable对象提交给指定的线程池，Future代表返回值。</li>
</ul>
<p>线程池使用步骤：<br>
1、调用Executors类的静态工厂方法创建一个ExecutorService对象。<br>
2、创建Runnable实现类或Callable实现类的实例。<br>
3、调用ExecutorService对象的submit()方法提交Runnable或Callable实例。<br>
4、调用ExecutorService对象的shutdown()关闭线程池。</p>
<p>示例代码片段：</p>
<pre><code class="language-java">
import java.util.concurrent.*;

public class ThreadPoolTest
{
    public static void main(String[] args)
        throws Exception
    {
        // 创建足够的线程来支持4个CPU并行的线程池
        // 创建一个具有固定线程数（6）的线程池
        ExecutorService pool = Executors.newFixedThreadPool(6);
        // 使用Lambda表达式创建Runnable对象
        Runnable target = () -&gt; {
            for (int i = 0; i &lt; 100 ; i++ )
            {
                System.out.println(Thread.currentThread().getName()
                    + &quot;的i值为:&quot; + i);
            }
        };
        // 向线程池中提交两个线程
        pool.submit(target);
        pool.submit(target);
        // 关闭线程池
        pool.shutdown();
    }
}
</code></pre>
<p>注意：《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建，而是通过 ThreadPoolExecutor 的方式 ——20190903</p>
<p>参考：https://snailclimb.gitee.io/javaguide/#/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions?id=_44-%e5%a6%82%e4%bd%95%e5%88%9b%e5%bb%ba%e7%ba%bf%e7%a8%8b%e6%b1%a0</p>
<pre><code class="language-java">        //构造一个线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                1, 
                1, 
                10, 
                TimeUnit.SECONDS,
                new ArrayBlockingQueue&lt;Runnable&gt;(1),
                new ThreadPoolExecutor.DiscardOldestPolicy());
        threadPool.execute(() -&gt; {
            try {
                //执行 方法
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                threadPool.shutdown();// 关闭线程池
            }
        });
</code></pre>
<p>参考：https://blog.csdn.net/qq_31615049/article/details/80756781</p>
<p>参考资料：</p>
<ul>
<li>ThreadPoolExecutor线程池解析及Executor创建线程常见四种方式：https://cloud.tencent.com/developer/article/1442947</li>
</ul>
<h2 id="forkjoinpool">ForkJoinPool</h2>
<p>jdk 7 提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算，再把多个“小任务”的结果合并成总的计算结果。</p>
<pre><code>java.util.concurrent.Executor
                    |-ExecutorService
                        |-AbstractExecutorService
                            |-ForkJoinPool
</code></pre>
<p>创建ForkJoinPool实例后，就可以调用ForkJoinPool的submit(ForkJoinTask task)或invoke(ForkJoinTask task)方法来提交任务。</p>
<p>其中ForkJoinTask有两个抽象子类：</p>
<pre><code>java.util.concurrent.Future
                    |-ForkJoinTask          表示一个可执行、合并的任务
                        |-RecursiveAction   表示没有返回值的任务
                        |-RecursiveTask     表示有返回值的任务
</code></pre>
<p>完整示例：</p>
<pre><code class="language-java">
import java.util.concurrent.*;

// 继承RecursiveAction来实现&quot;可分解&quot;的任务
class PrintTask extends RecursiveAction
{
    // 每个“小任务”只最多只打印50个数
    private static final int THRESHOLD = 50;
    private int start;
    private int end;
    // 打印从start到end的任务
    public PrintTask(int start, int end)
    {
        this.start = start;
        this.end = end;
    }
    @Override
    protected void compute()
    {
        // 当end与start之间的差小于THRESHOLD时，开始打印
        if(end - start &lt; THRESHOLD)
        {
            for (int i = start ; i &lt; end ; i++ )
            {
                System.out.println(Thread.currentThread().getName()
                    + &quot;的i值：&quot; + i);
            }
        }
        else
        {
            // 如果当end与start之间的差大于THRESHOLD时，即要打印的数超过50个
            // 将大任务分解成两个小任务。
            int middle = (start + end) / 2;
            PrintTask left = new PrintTask(start, middle);
            PrintTask right = new PrintTask(middle, end);
            // 并行执行两个“小任务”
            left.fork();
            right.fork();
        }
    }
}
public class ForkJoinPoolTest
{
    public static void main(String[] args)
        throws Exception
    {
        ForkJoinPool pool = new ForkJoinPool();
        // 提交可分解的PrintTask任务
        pool.submit(new PrintTask(0 , 300));
        pool.awaitTermination(2, TimeUnit.SECONDS);
        // 关闭线程池
        pool.shutdown();
    }
}


</code></pre>
<pre><code class="language-java">
import java.util.concurrent.*;
import java.util.*;

// 继承RecursiveTask来实现&quot;可分解&quot;的任务
class CalTask extends RecursiveTask&lt;Integer&gt;
{
    // 每个“小任务”只最多只累加20个数
    private static final int THRESHOLD = 20;
    private int arr[];
    private int start;
    private int end;
    // 累加从start到end的数组元素
    public CalTask(int[] arr , int start, int end)
    {
        this.arr = arr;
        this.start = start;
        this.end = end;
    }
    @Override
    protected Integer compute()
    {
        int sum = 0;
        // 当end与start之间的差小于THRESHOLD时，开始进行实际累加
        if(end - start &lt; THRESHOLD)
        {
            for (int i = start ; i &lt; end ; i++ )
            {
                sum += arr[i];
            }
            return sum;
        }
        else
        {
            // 如果当end与start之间的差大于THRESHOLD时，即要累加的数超过20个时
            // 将大任务分解成两个小任务。
            int middle = (start + end) / 2;
            CalTask left = new CalTask(arr , start, middle);
            CalTask right = new CalTask(arr , middle, end);
            // 并行执行两个“小任务”
            left.fork();
            right.fork();
            // 把两个“小任务”累加的结果合并起来
            return left.join() + right.join();    // ①
        }
    }
}
public class Sum
{
    public static void main(String[] args)
        throws Exception
    {
        int[] arr = new int[100];
        Random rand = new Random();
        int total = 0;
        // 初始化100个数字元素
        for (int i = 0 , len = arr.length; i &lt; len ; i++ )
        {
            int tmp = rand.nextInt(20);
            // 对数组元素赋值，并将数组元素的值添加到sum总和中。
            total += (arr[i] = tmp);
        }
        System.out.println(total);
        // 创建一个通用池
        ForkJoinPool pool = ForkJoinPool.commonPool();
        // 提交可分解的CalTask任务
        Future&lt;Integer&gt; future = pool.submit(new CalTask(arr , 0 , arr.length));
        System.out.println(future.get());
        // 关闭线程池
        pool.shutdown();
    }
}

</code></pre>
<h2 id="threadpoolexecutor">ThreadPoolExecutor</h2>
<p>构造方法：——20191112</p>
<pre><code class="language-java">    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue&lt;Runnable&gt; workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) 
</code></pre>
<p>参数说明：</p>
<ul>
<li>corePoolSize =&gt; 线程池核心线程数量</li>
<li>maximumPoolSize =&gt; 线程池最大数量</li>
<li>keepAliveTime =&gt; 空闲线程存活时间</li>
<li>unit =&gt; 时间单位</li>
<li>workQueue =&gt; 线程池所使用的缓冲队列</li>
<li>threadFactory =&gt; 线程池创建线程使用的工厂</li>
<li>handler =&gt; 线程池对拒绝任务的处理策略</li>
</ul>
<p>线程池执行任务逻辑和线程池参数的关系：</p>
<p><img src="https://gitee.com/rulerLwx/PicGo/raw/master/img/20200707171346.png" alt=""></p>
<p>总结：</p>
<ul>
<li>FixedThreadPool和SingleThreadExecutor =&gt; 允许的请求队列长度为Integer.MAX_VALUE，可能会堆积大量的请求，引起OOM异常</li>
<li>CachedThreadPool =&gt; 允许创建的线程数为Integer.MAX_VALUE，可能会创建大量的线程，从而引起OOM异常</li>
</ul>
<p>这就是为什么<strong>禁止使用Executors去创建线程池</strong>，而是推荐自己去创建ThreadPoolExecutor的原因</p>
<p>建议：</p>
<ul>
<li>CPU密集型 =&gt; 线程池的大小推荐为CPU数量 + 1，CPU数量可以根据Runtime.availableProcessors方法获取</li>
<li>IO密集型 =&gt; CPU数量 * CPU利用率 * (1 + 线程等待时间/线程CPU时间)</li>
<li>混合型 =&gt; 将任务分为CPU密集型和IO密集型，然后分别使用不同的线程池去处理，从而使每个线程池可以根据各自的工作负载来调整</li>
<li>阻塞队列 =&gt; 推荐使用有界队列，有界队列有助于避免资源耗尽的情况发生</li>
<li>拒绝策略 =&gt; 默认采用的是AbortPolicy拒绝策略</li>
</ul>
<p>拒绝策略推荐以下几种：</p>
<ul>
<li>在程序中捕获RejectedExecutionException异常，在捕获异常中对任务进行处理。针对默认拒绝策略</li>
<li>使用CallerRunsPolicy拒绝策略，该策略会将任务交给调用execute的线程执行【一般为主线程】，此时主线程将在一段时间内不能提交任何任务，从而使工作线程处理正在执行的任务。此时提交的线程将被保存在TCP队列中，TCP队列满将会影响客户端，这是一种平缓的性能降低</li>
<li>自定义拒绝策略，只需要实现RejectedExecutionHandler接口即可</li>
<li>如果任务不是特别重要，使用DiscardPolicy和DiscardOldestPolicy拒绝策略将任务丢弃也是可以的</li>
</ul>
<p>参考：https://mp.weixin.qq.com/s?__biz=MzIzMzgxOTQ5NA==&amp;mid=2247489522&amp;idx=1&amp;sn=e56c83eae436e177306a4d818d2ef73c&amp;chksm=e8fe8bfbdf8902eda75dd7afe069cf8d7a70b9b183b95035859a5ded5609956393a73a2f8b39&amp;scene=0&amp;xtrack=1&amp;key=e44a2e70ef44435d01bde76d941a30b6506a00995ec8cf19fa95c3d5ee8b57544d830087e7ab29c8434eb07794c21bde261b18a28e1858b1291c85bae22ccf792f586479406a61c561b5e93554fa90c0&amp;ascene=1&amp;uin=MjY0NjE5NjUzNQ%3D%3D&amp;devicetype=Windows+10&amp;version=62070158&amp;lang=zh_CN&amp;pass_ticket=r8eJN8itmJD5vwKgZydZdBltEvSKH06rU7D%2FNO6Ri%2F1h4CI188V3eAcJuyFqEFCZ</p>

    </div>
    <div class="article-footer">
<blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">
    <li class="post-copyright-link hidden-xs">
      <strong>Permalink: </strong>
      <a href="https://rulerLwx.gitee.io/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-1-%E5%9F%BA%E7%A1%80/" title="Java-Se-多线程-1-基础" target="_blank" rel="external">https://rulerLwx.gitee.io/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-1-%E5%9F%BA%E7%A1%80/</a>
    </li>
    <li class="post-copyright-license">
      <strong>License：</strong><a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN</a>
    </li>
  </ul>
</blockquote>

<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://gitee.com/rulerLwx" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="https://rulerLwx.gitee.io/avatar.png" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://gitee.com/rulerLwx" target="_blank"><span class="text-dark">rulerLwx</span><small class="ml-1x">thinking...</small></a></h3>
        <div>Good Good Study, Day Day Up~</div>
      </div>
    </figure>
  </div>
</div>
    </div>
  </article>
<section id="comments">
    <div id="vcomments"></div>
</section>

</div><nav class="bar bar-footer clearfix" data-stick-bottom>
    <div class="bar-inner">
        <ul class="pager pull-left">
            <li class="prev">
                <a href="https://rulerLwx.gitee.io/2020/07/java-se-%E5%A4%9A%E7%BA%BF%E7%A8%8B-2-%E9%AB%98%E7%BA%A7/" title="Java-Se-多线程-2-高级"><i
                        class="icon icon-angle-left"
                        aria-hidden="true"></i><span>&nbsp;&nbsp;Older</span></a>
            </li>
            <li class="next">
                <a href="https://rulerLwx.gitee.io/2020/07/java-se-%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/"
                    title="Java-Se-基本数据类型"><span>Newer&nbsp;&nbsp;</span><i
                        class="icon icon-angle-right" aria-hidden="true"></i></a>
            </li>
            
            <li class="toggle-toc">
                <a class="toggle-btn collapsed" data-toggle="collapse" href="#collapseToc" aria-expanded="false"
                    title="Catalogue" role="button">
                    <span>[&nbsp;</span><span>Catalogue</span>
                    <i class="text-collapsed icon icon-anchor"></i>
                    <i class="text-in icon icon-close"></i>
                    <span>]</span>
                </a>
            </li>
        </ul>
        <div class="bar-right">
            <div class="share-component" data-sites="weibo,qq,wechat"
                data-mobile-sites="weibo,qq,qzone"></div>
        </div>
    </div>
</nav>

</main><footer class="footer" itemscope itemtype="http://schema.org/WPFooter">
<ul class="social-links">
    <li><a href="https://gitee.com/rulerLwx" target="_blank" title="gitee" data-toggle=tooltip data-placement=top >
            <i class="icon icon-gitee"></i></a></li>
    <li><a href="https://github.com/wolf-lea" target="_blank" title="github" data-toggle=tooltip data-placement=top >
            <i class="icon icon-github"></i></a></li>
</ul>
  <div class="copyright">
    &copy;2020  -
    2020
    <div class="publishby">
        Theme by <a href="https://github.com/xiaoheiAh" target="_blank"> xiaoheiAh </a>base on<a href="https://github.com/xiaoheiAh/hugo-theme-pure" target="_blank"> pure</a>.
    </div>
  </div>
</footer>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_SVG"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
            showMathMenu: false, //disables context menu
            tex2jax: {
            inlineMath: [ ['$','$'], ['\\(','\\)'] ]
           }
    });
</script>


<script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.min.js"></script>
<script>
    window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/highlight.min.js"></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/python.min.js" defer></script>
<script type="text/javascript" src="https://cdn.staticfile.org/highlight.js/9.15.10/languages/javascript.min.js" defer></script><script>
    hljs.configure({
        tabReplace: '    ', 
        classPrefix: ''     
        
    })
    hljs.initHighlightingOnLoad();
</script>
<script src="https://rulerLwx.gitee.io/js/application.min.bdeb64b910570b6c41badc6a05b7afb0c8ad9efd8525de3c7257d59e786326a3.js"></script>
<script src="https://rulerLwx.gitee.io/js/plugin.min.51ff8c7317566f82259170fa36e09c4493adc9b9378b427a01ad3f017ebac7dd.js"></script>

<script>
    (function (window) {
        var INSIGHT_CONFIG = {
            TRANSLATION: {
                POSTS: 'Posts',
                PAGES: 'Pages',
                CATEGORIES: 'Categories',
                TAGS: 'Tags',
                UNTITLED: '(Untitled)',
            },
            ROOT_URL: 'https:\/\/rulerLwx.gitee.io',
            CONTENT_URL: 'https:\/\/rulerLwx.gitee.io\/searchindex.json ',
        };
        window.INSIGHT_CONFIG = INSIGHT_CONFIG;
    })(window);
</script>
<script type="text/javascript" src="https://rulerLwx.gitee.io/js/insight.min.a343cd9a5a7698336b28ef3a7c16a3a1b1d2d5fb17dc8ed04022bbe08cc5459073a15bdafa3a8a58cdd56080784bdd69fa70b1ae8597565c799c57ed00f0e120.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.4.2/tocbot.min.js"></script>
<script>
    tocbot.init({
        
        tocSelector: '.js-toc',
        
        contentSelector: '.js-toc-content',
        
        headingSelector: 'h1, h2, h3',
        
        hasInnerContainers: true,
    });
</script>

<script src="https://cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/valine"></script>
<script type="text/javascript">
    var GUEST = ['nick', 'mail', 'link'];
    var meta = 'nick,mail';
    meta = meta.split(',').filter(function (item) {
        return GUEST.indexOf(item) > -1;
    });
    new Valine({
        el: '#vcomments',
        verify: null ,
        notify: null ,
        appId: 'IyAB0PSPRazTPDxitO1ddQ7O-gzGzoHsz',
        appKey: '5rBJTq4KidYF33eXwvRVhtEH',
        placeholder: 'enjoy~',
        avatar: 'mm',
        meta: meta,
        pageSize: '10' || 10,
        visitor: false 
});
</script>

  </body>
</html>
